using System;
using System.Globalization;
using Windows.UI.Xaml;
using System.Reflection;

namespace System.Windows.Interactivity
{
	/// <summary>
	/// Encapsulates state information and zero or more ICommands into an attachable object.
	/// </summary>
	/// <remarks>This is an infrastructure class. Behavior authors should derive from Behavior&lt;T&gt; instead of from this class.</remarks>
    public abstract class Behavior : FrameworkElement, IAttachedObject
	{
		private Type associatedType;
		private DependencyObject associatedObject;
		internal event EventHandler AssociatedObjectChanged;
		/// <summary>
		/// The type to which this behavior can be attached.
		/// </summary>
		protected Type AssociatedType
		{
			get
			{
				return this.associatedType;
			}
		}
		/// <summary>
		/// Gets the object to which this behavior is attached.
		/// </summary>
		protected DependencyObject AssociatedObject
		{
			get
			{
				return this.associatedObject;
			}
		}
		/// <summary>
		/// Gets the associated object.
		/// </summary>
		/// <value>The associated object.</value>
		DependencyObject IAttachedObject.AssociatedObject
		{
			get
			{
				return this.AssociatedObject;
			}
		}
		internal Behavior(Type associatedType)
		{
			this.associatedType = associatedType;
		}
		/// <summary>
		/// Called after the behavior is attached to an AssociatedObject.
		/// </summary>
		/// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>
		protected virtual void OnAttached()
		{
		}
		/// <summary>
		/// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
		/// </summary>
		/// <remarks>Override this to unhook functionality from the AssociatedObject.</remarks>
		protected virtual void OnDetaching()
		{
		}
        //protected override Freezable CreateInstanceCore()
        //{
        //    Type type = base.GetType();
        //    return (Freezable)Activator.CreateInstance(type);
        //}
		private void OnAssociatedObjectChanged()
		{
			if (this.AssociatedObjectChanged != null)
			{
				this.AssociatedObjectChanged(this, new EventArgs());
			}
		}
		/// <summary>
		/// Attaches to the specified object.
		/// </summary>
		/// <param name="dependencyObject">The object to attach to.</param>
		/// <exception cref="T:System.InvalidOperationException">The Behavior is already hosted on a different element.</exception>
		/// <exception cref="T:System.InvalidOperationException">dependencyObject does not satisfy the Behavior type constraint.</exception>
		public void Attach(DependencyObject dependencyObject)
		{
			if (dependencyObject != this.AssociatedObject)
			{
				if (this.AssociatedObject != null)
				{
					throw new InvalidOperationException("CannotHostBehaviorMultipleTimesExceptionMessage");
				}
				if (dependencyObject != null && !this.AssociatedType.GetTypeInfo().IsAssignableFrom(dependencyObject.GetType().GetTypeInfo()))
				{
					throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "TypeConstraintViolatedExceptionMessage", new object[]
					{
						base.GetType().Name,
						dependencyObject.GetType().Name,
						this.AssociatedType.Name
					}));
				}
				this.associatedObject = dependencyObject;
				this.OnAssociatedObjectChanged();
				this.OnAttached();
			}
		}
		/// <summary>
		/// Detaches this instance from its associated object.
		/// </summary>
		public void Detach()
		{
			this.OnDetaching();
			this.associatedObject = null;
			this.OnAssociatedObjectChanged();
		}
	}
}
